package org.lc.stk.service.course.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.lc.stk.dao.course.ChapterRepository;
import org.lc.stk.dao.course.CourseRepository;
import org.lc.stk.model.course.Chapter;
import org.lc.stk.model.course.Course;
import org.lc.stk.service.course.ChapterService;
import org.lc.stk.service.exception.BusinessException;
import org.lc.stk.model.course.Chapter.ChapterState;
import org.lc.stk.web.dto.chapter.ChapterTreeResponseDTO;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service
@Transactional(readOnly = true)
public class ChapterServiceImpl implements ChapterService {

    private final ChapterRepository chapterRepository;
    private final CourseRepository courseRepository;

    public ChapterServiceImpl(ChapterRepository chapterRepository, CourseRepository courseRepository) {
        this.chapterRepository = chapterRepository;
        this.courseRepository = courseRepository;
    }

    @Override
    @Transactional
    public Chapter createChapter(Integer courseId, Integer parentId, Chapter chapter) {
        // 验证课程是否存在
        Course course = courseRepository.findById(courseId)
                .orElseThrow(() -> new BusinessException("课程不存在: " + courseId));

        // 验证父章节
        Chapter parent = null;
        if (parentId != null) {
            parent = chapterRepository.findById(parentId)
                    .orElseThrow(() -> new BusinessException("父章节不存在: " + parentId));
            
            // 验证父章节是否属于同一课程
            if (!parent.getCourse().getId().equals(courseId)) {
                throw new BusinessException("父章节不属于指定课程");
            }
        }

        // 验证必填字段
        validateChapter(chapter);

        // 设置关联关系
        chapter.setCourse(course);
        chapter.setParent(parent);

        // 设置排序号
        if (chapter.getSort() == null) {
            chapter.setSort(getNextSort(courseId, parentId));
        } else {
            // 验证排序号是否重复
            if (isSortExists(courseId, parentId, chapter.getSort(), null)) {
                throw new BusinessException("当前层级下已存在相同的排序号: " + chapter.getSort());
            }
        }

        return chapterRepository.save(chapter);
    }

    @Override
    @Transactional
    public Chapter updateChapter(Integer id, Chapter chapter) {
        Chapter existingChapter = chapterRepository.findById(id)
                .orElseThrow(() -> new BusinessException("章节不存在: " + id));

        // 验证必填字段
        validateChapter(chapter);

        // 如果更改了排序号，需要验证是否重复
        if (!Objects.equals(existingChapter.getSort(), chapter.getSort())) {
            if (isSortExists(existingChapter.getCourse().getId(), 
                    existingChapter.getParent() != null ? existingChapter.getParent().getId() : null,
                    chapter.getSort(), id)) {
                throw new BusinessException("当前层级下已存在相同的排序号: " + chapter.getSort());
            }
        }

        // 更新字段
        existingChapter.setName(chapter.getName());
        existingChapter.setSort(chapter.getSort());

        return chapterRepository.save(existingChapter);
    }

    /**
     * 检查是否存在子章节，并且是否存在试题
     * TODO 检查是否存在试题
     */
    @Override
    @Transactional
    public void deleteChapter(Integer id) {
        Chapter chapter = chapterRepository.findById(id)
                .orElseThrow(() -> new BusinessException("章节不存在: " + id));
        
        // 检查是否存在子章节
        if (!chapter.getChildren().isEmpty()) {
            throw new BusinessException("请先删除子章节");
        }
    
        // 软删除：设置状态为INACTIVE表示已停用
        chapter.setState(ChapterState.INACTIVE);
        chapterRepository.save(chapter);
    }

    @Override
    public Optional<Chapter> getChapterById(Integer id) {
        return chapterRepository.findById(id);
    }

    @Override
    public List<Chapter> getRootChapters(Integer courseId) {
        return chapterRepository.findByCourseIdAndParentIsNull(courseId, Sort.by("sort"));
    }

    @Override
    public List<Chapter> getChildChapters(Integer parentId) {
        return chapterRepository.findByParentId(parentId, Sort.by("sort"));
    }

    @Override
    @Transactional
    public Chapter moveChapter(Integer id, Integer newSort) {
        Chapter chapter = chapterRepository.findById(id)
                .orElseThrow(() -> new BusinessException("章节不存在: " + id));

        if (Objects.equals(chapter.getSort(), newSort)) {
            return chapter;
        }

        Integer courseId = chapter.getCourse().getId();
        Integer parentId = chapter.getParent() != null ? chapter.getParent().getId() : null;

        if (isSortExists(courseId, parentId, newSort, id)) {
            throw new BusinessException("当前层级下已存在相同的排序号: " + newSort);
        }

        chapter.setSort(newSort);
        return chapterRepository.save(chapter);
    }

    @Override
    public String getChapterPath(Integer id) {
        List<String> path = new ArrayList<>();
        Chapter current = chapterRepository.findById(id)
                .orElseThrow(() -> new BusinessException("章节不存在: " + id));

        while (current != null) {
            path.add(0, current.getName());
            current = current.getParent();
        }

        return String.join("/", path);
    }

    @Override
    public boolean isSortExists(Integer courseId, Integer parentId, Integer sort, Integer excludeId) {
        return chapterRepository.existsByCourseIdAndParentIdAndSort(courseId, parentId, sort);
    }

    @Override
    public Integer getNextSort(Integer courseId, Integer parentId) {
        Optional<Integer> maxSort = parentId != null ?
                chapterRepository.findMaxSortByParentId(courseId, parentId) :
                chapterRepository.findMaxRootSort(courseId);
        return maxSort.map(s -> s + 1).orElse(1);
    }

    @Override
    public List<Chapter> searchChapters(Integer courseId, String name) {
        if (!StringUtils.hasText(name)) {
            return Collections.emptyList();
        }
        return chapterRepository.findByCourseIdAndNameContaining(courseId, name, Sort.by("sort"));
    }

    @Override
    public int getChapterLevel(Integer id) {
        int level = 1;
        Chapter current = chapterRepository.findById(id)
                .orElseThrow(() -> new BusinessException("章节不存在: " + id));

        while (current.getParent() != null) {
            level++;
            current = current.getParent();
        }

        return level;
    }

    private void validateChapter(Chapter chapter) {
        if (!StringUtils.hasText(chapter.getName())) {
            throw new BusinessException("章节名称不能为空");
        }

        if (chapter.getSort() != null && chapter.getSort() <= 0) {
            throw new BusinessException("章节序号必须大于0");
        }
    }

    @Override
    public List<ChapterTreeResponseDTO> getChapterTree(Integer courseId) {
        // 验证课程是否存在
        if (!courseRepository.existsById(courseId)) {
            throw new BusinessException("课程不存在: " + courseId);
        }

        // 获取根章节列表
        List<Chapter> rootChapters = getRootChapters(courseId);
        return buildChapterTree(rootChapters);
    }

    private List<ChapterTreeResponseDTO> buildChapterTree(List<Chapter> chapters) {
        return chapters.stream()
                .map(this::convertToTreeDTO)
                .sorted((a, b) -> {
                    if (a.getSort() == null || b.getSort() == null) {
                        return 0;
                    }
                    return a.getSort().compareTo(b.getSort());
                })
                .collect(Collectors.toList());
    }

    private ChapterTreeResponseDTO convertToTreeDTO(Chapter chapter) {
        ChapterTreeResponseDTO dto = new ChapterTreeResponseDTO();
        dto.setId(chapter.getId());
        dto.setName(chapter.getName());
        dto.setSort(chapter.getSort());
        
        if (chapter.getChildren() != null && !chapter.getChildren().isEmpty()) {
            dto.setChildren(buildChapterTree(chapter.getChildren()));
        }
        
        return dto;
    }
}
